﻿using System.Collections;

namespace FileNameProvider
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Runtime.Serialization.Formatters.Binary;
    using MediaSage.Lib;
    using MediaSage.Lib.Configuration;
    using MediaSage.Lib.Database;
    using Tst;

    public class Titles
    {
        private readonly Config config;
        private readonly Logger logger;
        private Tst.TstDictionary staticDictionary = null;
        private Tst.TstDictionary dynamicDictionary = null;
        private bool useStaticDictionary = false;
        private readonly PluginEntity pluginEntity;
        private string dynamicDataFilename = null;

        public Titles(Config Config, bool UseMovieNameDB, PluginEntity pe)
        {
            config = Config;
            logger = config.Logger;
            pluginEntity = pe;

            logger.Log("Initializing FileNameProvider.Titles");
            useStaticDictionary = UseMovieNameDB;
            logger.Log(string.Format("useStaticDictionary={0}", useStaticDictionary.ToString()));

            useStaticDictionary = InitializeDictionaries();
        }

        ~Titles()
        {
            if (dynamicDictionary != null)
            {
                logger.Log("Saving user movie dictionary");
                dynamicDictionary.Save(dynamicDataFilename);
            }
        }

        public void AddTitle(string title)
        {
            logger.Log("Entering FileNameProvider.Titles.AddTitle(" + title + ")");
            if (this.TitleExists(title))
            {
                logger.Log("Title already exists, exiting");
                logger.Log("Exiting FileNameProvider.Titles.AddTitle(" + title + ")");
                return;
            }

            dynamicDictionary.Add(title, String.Empty);
            logger.Log("Exiting FileNameProvider.Titles.AddTitle(" + title + ")");
        }

        private bool InitializeDictionaries()
        {
            logger.Log("Entering FileNameProvider.Titles.initializeStaticTrie()");
            string movieDatFilename = null;
            bool useStatic = false;
            bool loadDynamic = false;
            if (useStaticDictionary)
            {
                if (File.Exists(Path.Combine(Path.GetDirectoryName(pluginEntity.Location), "IMDBTitles.dat")))
                {
                    movieDatFilename = Path.Combine(Path.GetDirectoryName(pluginEntity.Location), "IMDBTitles.dat");
                }
                else
                {
                    if (File.Exists(Path.Combine(Directory.GetCurrentDirectory(), "IMDBTitles.dat")))
                    {
                        movieDatFilename = Path.Combine(Directory.GetCurrentDirectory(), "IMDBTitles.dat");
                    }
                    else
                    {
                        logger.Log(Logger.Levels.ERROR, "Could not find IMDBTitles.dat, reinstall plugin");
                        logger.Log(Logger.Levels.WARN, "Will not use MovieNameDB");
                    }
                }
            }
            if (File.Exists(Path.Combine(Path.GetFullPath(pluginEntity.Location), "UserTitles.dat")))
            {
                dynamicDataFilename = Path.Combine(Path.GetDirectoryName(pluginEntity.Location), "UserTitles.dat");
                loadDynamic = true;
            }
            else
            {
                if (File.Exists(Path.Combine(Directory.GetCurrentDirectory(), "UserTitles.dat")))
                {
                    dynamicDataFilename = Path.Combine(Directory.GetCurrentDirectory(), "UserTitles.dat");
                    loadDynamic = true;
                }
                else
                {
                    dynamicDataFilename = Path.Combine(Path.GetDirectoryName(pluginEntity.Location), "UserTitles.dat");
                }
            }

            if (movieDatFilename != null)
            {
                Stream stream = null;
                try
                {
                    stream = File.Open(movieDatFilename, FileMode.Open);
                    var bFormatter = new BinaryFormatter();
                    staticDictionary = (TstDictionary)bFormatter.Deserialize(stream);
                    stream.Close();
                    logger.Log("Movie Database initialized");
                    useStatic = true;
                }
                catch (Exception e)
                {
                    logger.Log("Exception initializing movie database: " + e.Message);
                    if (stream != null)
                    {
                        stream.Close();
                    }
                    staticDictionary = null;
                    logger.Log("Exiting FileNameProvider.Titles.initializeStaticTrie(), rc==false");
                }
            }

            if (loadDynamic)
            {
                logger.Log(String.Format("Loading {0}", dynamicDataFilename));
                Stream stream = null;
                try
                {
                    stream = File.Open(dynamicDataFilename, FileMode.Create);
                    var bFormatter = new BinaryFormatter();
                    dynamicDictionary = (TstDictionary)bFormatter.Deserialize(stream);
                    stream.Close();
                    logger.Log("User movie Database initialized");
                }
                catch (Exception e)
                {
                    logger.Log("Exception initializing movie database: " + e.Message);
                    if (stream != null)
                    {
                        stream.Close();
                    }
                    loadDynamic = false;
                }
            }

            if (!loadDynamic)
            {
                logger.Log(String.Format("Creating user movie database: {0}", dynamicDataFilename));
                dynamicDictionary = new TstDictionary();
            }

            logger.Log("Exiting FileNameProvider.Titles.initializeStaticTrie(), rc==true");
            return useStatic;
        }

        public bool TitleExists(string title)
        {
            logger.Log(String.Format("Entering FileNameProvider.Titles.TitleExists({0})", title));
            if (useStaticDictionary)
            {
                if (staticDictionary.Contains(title))
                {
                    logger.Log(String.Format("Exiting FileNameProvider.Titles.TitleExists({0}), rc==true", title));
                    return true;
                }
            }
            if (dynamicDictionary != null)
            {
                if (dynamicDictionary.Contains(title))
                {
                    logger.Log(String.Format("Exiting FileNameProvider.Titles.TitleExists({0}), rc==true", title));
                    return true;
                }
            }
            logger.Log(String.Format("Exiting FileNameProvider.Titles.TitleExists({0}), rc==false", title));
            return false;
        }

        public void Save()
        {
            logger.Log("Entering FileNameProvider.Titles.Save()");
            dynamicDictionary.Save(dynamicDataFilename);
        }

        public IList<string> GetFuzzyMatches(string title, int distance)
        {
            logger.Log(String.Format("Entering FileNameProvider.Titles.TitleExistsFuzzy({0},{1})", title, distance));
            IList<string> returnValues = new List<string>();
            if (useStaticDictionary)
            {
                if (title.Length > 2)
                {
                    var list = staticDictionary.NearNeighbors(title, distance);
                    foreach (DictionaryEntry kvp in list)
                    {
                        returnValues.Add(kvp.Key.ToString());
                    }
                }
            }
            if (dynamicDictionary != null)
            {
                var list = dynamicDictionary.NearNeighbors(title, distance);
                foreach (DictionaryEntry kvp in list)
                {
                    returnValues.Add(kvp.Key.ToString());
                }
            }
            logger.Log(String.Format("Exiting FileNameProvider.Titles.TitleExists({0},{1}), with {2} matches", title, distance, returnValues.Count));
            return (returnValues);
        }
    }
}